package com.tensai.core.config;

import com.tensai.core.mvc.base.tools.ResultJson;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.TypeMismatchException;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;

/**
 * controller 增强器
 * 异常处理
 *
 * @author tensai
 * @since 2017/7/17
 */
@Slf4j
@ControllerAdvice
@ResponseBody
public class MyControllerAdvice {

    private static final String logExceptionFormat = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";

    /**
     * 运行时异常处理方法（请求方法不支持）405
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler(RuntimeException.class)
    public ResultJson runtimeExceptionHandler(RuntimeException ex) {
        return resultFormat(1, ex);
    }

    /**
     * 空指针异常处理方法
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler(NullPointerException.class)
    public ResultJson nullPointerExceptionHandler(NullPointerException ex) {
        return resultFormat(2, ex);
    }

    //类型转换异常
    /**
     * 请求方法不一致异常处理方法（请求方法不支持）405
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler(ClassCastException.class)
    public ResultJson classCastExceptionHandler(ClassCastException ex) {
        return resultFormat(3, ex);
    }

    /**
     * IO异常处理方法
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler(IOException.class)
    public ResultJson iOExceptionHandler(IOException ex) {
        return resultFormat(4, ex);
    }

    /**
     * 未知方法异常处理方法
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler(NoSuchMethodException.class)
    public ResultJson noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return resultFormat(5, ex);
    }

    /**
     * 数组越界异常处理方法
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public ResultJson indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return resultFormat(6, ex);
    }

    /**
     * 参数类型不一致异常处理方法 400
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ResultJson requestNotReadable(HttpMessageNotReadableException ex) {
        return resultFormat(7, ex);
    }

    /**
     * 类型不匹配异常处理方法 400
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({TypeMismatchException.class})
    public ResultJson requestTypeMismatch(TypeMismatchException ex) {
        return resultFormat(8, ex);
    }

    /**
     * 请求参数丢失异常处理方法 400
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public ResultJson requestMissingServletRequest(MissingServletRequestParameterException ex) {
        return resultFormat(9, ex);
    }

    /**
     * 请求方法不一致异常处理方法（请求方法不支持）405
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ResultJson request405(HttpRequestMethodNotSupportedException ex) {
        return resultFormat(10, ex);
    }

    /**
     * 媒体类型不一致异常处理方法 406
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public ResultJson request406(HttpMediaTypeNotAcceptableException ex) {
        return resultFormat(11, ex);
    }

    /**
     * 运行时异常处理方法（转换器异常、Message异常写）500
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public ResultJson server500(RuntimeException ex) {
        return resultFormat(12, ex);
    }

    /**
     * 栈溢出异常处理方法
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({StackOverflowError.class})
    public ResultJson requestStackOverflow(StackOverflowError ex) {
        return resultFormat(13, ex);
    }

    /**
     * 其他异常处理方法
     *
     * @param ex 异常
     * @return 异常处理返回
     */
    @ExceptionHandler({Exception.class})
    public ResultJson exception(Exception ex) {
        return resultFormat(14, ex);
    }

    private <T extends Throwable> ResultJson resultFormat(Integer code, T ex) {
        ex.printStackTrace();
        log.error(String.format(logExceptionFormat, code, ex.getMessage()));
        return new ResultJson(code, ex.getMessage());
    }


}

